from django.utils.datastructures import SortedDict
from django.utils.importlib import import_module
from django.core.exceptions import ImproperlyConfigured
from django.db import models
from django.conf import settings
from django.contrib.auth.models import User
from django.db.models.signals import post_save

# Plugins load stuff
plugins = None # Plugin dictionary, will be loaded on the first call to get_conduit_plugin

def load_plugin(path):
    """Loads a plugin from it's string name. Inspired in django.contrib.auth.load_backend'"""
    i = path.rfind('.')
    module, attr = path[:i], path[i+1:]
    try:
        mod = import_module(module)
    except ImportError, e:
        raise ImproperlyConfigured, 'Error importing authentication backend %s: "%s"' % (module, e)
    except ValueError, e:
        raise ImproperlyConfigured, 'Error importing authentication backends. Is CONDUIT_PLUGINS a correctly defined list or tuple?'
    try:
        cls = getattr(mod, attr)
    except AttributeError:
        raise ImproperlyConfigured, 'Module "%s" does not define a "%s" conduit plugin' % (module, attr)
    return cls


def load_conduit_plugins():
    global plugins
    plugins = SortedDict()
    for plugin_path in settings.CONDUIT_PLUGINS:
        p = load_plugin(plugin_path)
        plugins[p.key] = p
    return plugins


def get_conduit_plugin(pluginName):
    global plugins
    if plugins is None:
        plugins = load_conduit_plugins()
    try:
        return plugins[pluginName]
    except KeyError:
        raise RuntimeError("Plugin %s doesn't exists in CONDUIT_PLUGINS" % pluginName)


def get_conduit_plugins():
    global plugins
    if plugins is None:
        plugins = load_conduit_plugins()
    return plugins.values()


def autoAddConduits(sender, instance, **kargs):
    """Notifies each plugin to see if they can add automatically a conduit based on user info."""
    currentConduits = Conduit.objects.filter(user=instance)
    for plugin in get_conduit_plugins():
        plugin.autoAddConduits(instance, currentConduits)

post_save.connect(autoAddConduits, sender=User)

# Create your models here.
class Conduit(models.Model):
    name = models.CharField(max_length=200)
    plugin = models.CharField("Conduit Type", max_length=20,
        choices=[(p.key, p.name) for p in get_conduit_plugins()])
    params = models.TextField(help_text="Plugin's parameters as a Python dict")
    user = models.ForeignKey(User)

    def __unicode__(self):
        return "%s - %s - Plugin: %s" % (self.user, self.name, self.plugin)

    def sendFeed(self, subscription, feed):
        plugin = get_conduit_plugin(self.plugin)(**eval(self.params))
        return plugin.sendFeed(subscription, feed)

    def getPluginName(self):
        return get_conduit_plugin(self.plugin).name
